//
// Created by jasonzhuang on 15-12-1.
//
#include <math.h>

#include <algorithm>

#include "SpreadCalc.h"

double mean(const std::vector<double>& spreads) {
  double sum = 0.0;
  double spreadSize = spreads.size();
  for (int i = 0; i < spreadSize; ++i) {
    sum += spreads[i];
  }
  return sum / spreads.size();
}

double stdDev(const std::vector<double>& spreads, const double mean) {
  double sum = 0.0;
  double spreadSize = spreads.size();
  for (int i = 0; i < spreadSize; ++i) {
    sum += (spreads[i] - mean) * (spreads[i] - mean);
  }
  return sqrt(sum / spreads.size());
}

double biasedMean(const double latest, const double mean) {
  return latest - mean;
}

double biasedStdDev(const double biasedMean, const double stdDev) {
  if (abs(stdDev) <= 1e-15) return 0.0;
  return biasedMean / stdDev;
}

double medium(const std::vector<double>& spreads) {
  int spreadSize = (int)spreads.size();
  std::vector<double> temp = spreads;
  std::sort(temp.begin(), temp.end());
  if (spreadSize % 2 == 1) {
    return temp[spreadSize / 2];
  } else {
    return (temp[spreadSize / 2 - 1] + temp[spreadSize / 2]) / 2.0;
  }
}

double percentage(const std::vector<double>& spreads) {
  int spreadSize = (int)spreads.size();
  double lastest = spreads[spreadSize - 1];
  double res = 0;
  for (int i = 0; i < spreadSize - 1; ++i) {
    if (lastest > spreads[i]) {
      ++res;
    }
  }
  return res / spreadSize;
}

int maxdata(const std::vector<double>& spreads) {
  double temp = spreads[0];
  int temp_offset = 0;
  int spreadSize = (int)spreads.size();
  for (int i = 1; i < spreadSize; ++i) {
    if (temp < spreads[i]) {
      temp = spreads[i];
      temp_offset = i;
    }
  }
  return temp_offset;
}

int mindata(const std::vector<double>& spreads) {
  double temp = spreads[0];
  int temp_offset = 0;
  int spreadSize = (int)spreads.size();
  for (int i = 1; i < spreadSize; ++i) {
    if (temp > spreads[i]) {
      temp = spreads[i];
      temp_offset = i;
    }
  }
  return temp_offset;
}

void calculateSpreadSeries(const std::vector<double>& spreads,
                           SpreadSeriesResult& res) {
  if (spreads.size() == 0) return;
  res.mean = mean(spreads);
  res.standardDeviation = stdDev(spreads, res.mean);
  res.biasedMean = biasedMean(spreads[spreads.size() - 1], res.mean);
  res.biasedStandardDeviation =
      biasedStdDev(res.biasedMean, res.standardDeviation);
  res.medium = medium(spreads);
  res.max_offset = maxdata(spreads);
  res.min_offset = mindata(spreads);
  res.percentage = percentage(spreads);
}
